package com.company.gobang.module.hall.service;

import com.company.gobang.module.room.RoomManager;
import com.company.gobang.module.room.domain.Room;
import com.company.gobang.module.room.event.RoomStartEvent;
import com.company.gobang.proto.*;
import xyz.noark.core.annotation.Autowired;
import xyz.noark.core.annotation.Service;
import xyz.noark.core.event.EventManager;
import xyz.noark.core.network.*;
import xyz.noark.core.network.Session.State;
import xyz.noark.core.util.MapUtils;
import xyz.noark.log.Logger;
import xyz.noark.log.LoggerFactory;
import xyz.noark.network.SocketSession;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

/**
 * 大厅业务类.
 *
 * @author 小流氓[176543888@qq.com]
 */
@Service
public class HallService {
    private static final Logger logger = LoggerFactory.getLogger(HallService.class);
    private static final SessionAttrKey<String> SESSION_NAME = SessionAttrKey.valueOf("name");
    /**
     * 已进入大厅的玩家，key=名称-->>value=玩家ID
     */
    private final Map<String, String> name2PlayerIdMap = MapUtils.newHashMap(256);

    @Autowired
    private EventManager eventManager;

    /**
     * 创建用户
     */
    public NetworkProtocol createReq(SocketSession session, String name) {
        // 名称被人占用了，提示他换个名字...
        if (name2PlayerIdMap.containsKey(name)) {
            return ErrorCodePush.createWarn("名称重复了，请重新取一个名字...");
        }

        // 假装这货登录成功，给他生成一个玩家ID
        String playerId = UUID.randomUUID().toString();
        session.setPlayerId(playerId);
        session.setState(State.INGAME);
        SessionManager.bindPlayerIdAndSession(playerId, session);
        logger.info("创建用户 playerId={}, name={}", playerId, name);

        // 把名称缓存到Session里
        session.attr(SESSION_NAME).set(name);


        // 进入大厅，绑定名称与玩家的关系
        name2PlayerIdMap.put(name, playerId);

        // 把目前大厅里的玩家推送给这个玩家
        this.pushUserList(playerId);

        // 把这个玩家推送给大厅里其他玩家
        if (name2PlayerIdMap.size() > 1) {
            Set<String> playerIdList = new HashSet<>(name2PlayerIdMap.values());
            playerIdList.remove(playerId);
            if (!playerIdList.isEmpty()) {
                UserAddPush push = new UserAddPush(name);
                // 这里的Opcode没有意义，那就忽略吧~~~
                Sender.relayPacket(playerIdList.toArray(new String[0]), "", push);
            }
        }

        // 搞个返回协议
        return ErrorCodePush.createSuccess("创建用户成功!!");
    }

    /**
     * 获取用户列表请求
     */
    public void listReq(String playerId) {
        this.pushUserList(playerId);
    }

    /**
     * 推送当前大厅里的玩家列表给这个玩家
     *
     * @param playerId 玩家ID
     */
    public void pushUserList(String playerId) {
        Set<String> nameSet = new HashSet<>(name2PlayerIdMap.keySet());
        Sender.relayPacket(playerId, "", new UserListPush(nameSet));
    }

    /**
     * 发起跳请求.
     */
    public NetworkProtocol challengeReq(String playerId, Session session, String targetName) {
        // 获取挑战的目标
        String targetPlayerId = name2PlayerIdMap.get(targetName);

        // 已离线了...
        if (targetPlayerId == null) {
            return ErrorCodePush.createWarn("目标[" + targetName + "]已离线...");
        }

        // 不能打自己吧...
        if (targetPlayerId.equals(playerId)) {
            return ErrorCodePush.createWarn("不能挑战自己...");
        }

        // 给对方发一个挑战通知
        String myName = session.attr(SESSION_NAME).get();
        Sender.relayPacket(targetPlayerId, "", new ChallengeNoticePush(myName));

        // 给自己一个响应
        return ErrorCodePush.createSuccess("已通知对方");
    }

    /**
     * 是否同意
     */
    public void gameReq(String playerId, boolean agree, String targetName111, String targetName) {
        String targetPlayerId = name2PlayerIdMap.get(targetName);
        // 同意挑战
        if (agree) {
            Room room = RoomManager.getInstance().createRoom();
            room.enter(playerId);
            room.enter(targetPlayerId);
            // 发布房间开始事件，由大厅线程切换去房间线程继续后继的逻辑
            eventManager.publish(new RoomStartEvent(room.getId()));
        }
        // 不同意挑战
        else {
            if (SessionManager.isOnline(targetPlayerId)) {
                ChallengeRefusePush push = new ChallengeRefusePush("很抱歉，目标[" + targetName111 + "]拒绝了您的请求...");
                Sender.relayPacket(targetPlayerId, "", push);
            }
        }
    }
}
